package utils

import (
	"errors"
	"fmt"
	"go.bug.st/serial.v1"
	"log"
	"time"
)

// SerialPort 串口操作结构体
type SerialPort struct {
	port     serial.Port
	isOpen   bool
	portName string
	mode     *serial.Mode
}

// NewSerialPort 创建新的串口实例
func NewSerialPort(portName string, baudRate int) *SerialPort {
	return &SerialPort{
		portName: portName,
		isOpen:   false,
		mode: &serial.Mode{
			BaudRate: baudRate,
			DataBits: 8,
			Parity:   serial.NoParity,
			StopBits: serial.OneStopBit,
		},
	}
}

func Init() *SerialPort {
	targetDevice := DeviceFilter{
		VID:          "04E2", // 替换为你的设备VID
		PID:          "",     // 替换为你的设备PID
		SerialNumber: "",     // 替换为你的设备序列号（可选）
	}

	portName, err := FindSerialPort(targetDevice)
	if err != nil {
		fmt.Printf("查找失败: %v\n", err)
		return nil
	}
	port := NewSerialPort(portName, 38400)
	return port
}

func IsOnline() bool {
	targetDevice := DeviceFilter{
		VID:          "04E2", // 替换为你的设备VID
		PID:          "",     // 替换为你的设备PID
		SerialNumber: "",     // 替换为你的设备序列号（可选）
	}

	portName, err := FindSerialPort(targetDevice)
	if err != nil {
		fmt.Printf("查找失败: %v\n", err)
		return false
	}

	fmt.Println("串口名称：", portName)
	return true
}

// SetMode 设置串口参数
func (s *SerialPort) SetMode(dataBits int, parity serial.Parity, stopBits serial.StopBits) {
	s.mode.DataBits = dataBits
	s.mode.Parity = parity
	s.mode.StopBits = stopBits
}

// Open 打开串口
func (s *SerialPort) Open() error {
	if s.isOpen {
		return errors.New("串口已打开")
	}

	port, err := serial.Open(s.portName, s.mode)
	if err != nil {
		return err
	}

	s.port = port
	s.isOpen = true
	return nil
}

// Close 关闭串口
func (s *SerialPort) Close() error {
	if !s.isOpen {
		return errors.New("串口未打开")
	}
	err := s.port.Close()
	if err != nil {
		return err
	}
	s.isOpen = false
	s.port = nil
	return nil
}

// SendCommand 发送指令到串口
func (s *SerialPort) SendCommand(command []byte) (int, error) {
	if !s.isOpen {
		return 0, errors.New("串口未打开")
	}
	return s.port.Write(command)
}

// SendString 发送字符串到串口
func (s *SerialPort) SendString(command string) (int, error) {
	return s.SendCommand([]byte(command))
}

// Read 从串口读取数据
func (s *SerialPort) Read(buffer []byte) (int, error) {
	if !s.isOpen {
		return 0, errors.New("串口未打开")
	}
	return s.port.Read(buffer)
}

// IsOpen 检查串口是否打开
func (s *SerialPort) IsOpen() bool {
	return s.isOpen
}

// GetPortName 获取串口名称
func (s *SerialPort) GetPortName() string {
	return s.portName
}

// ListPorts 列出所有可用串口
func ListPorts() ([]string, error) {
	return serial.GetPortsList()
}

// PrintPorts 打印所有可用串口
func PrintPorts() {
	ports, err := ListPorts()
	if err != nil {
		log.Printf("获取串口列表失败: %v", err)
		return
	}

	if len(ports) == 0 {
		log.Println("没有找到可用的串口")
		return
	}

	log.Println("可用串口:")
	for _, port := range ports {
		log.Printf("  %s", port)
	}
}

func (s *SerialPort) Stop() {
	s.Open()
	payload := []byte{0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}
	s.SendCommand(payload)
	defer s.Close()
}

func (s *SerialPort) Down() {
	s.Open()
	payload := []byte{0xFE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xFF}
	s.SendCommand(payload)
	defer s.Close()
}

func (s *SerialPort) Up() {

	s.Open()
	payload := []byte{0xFE, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0xFF}
	s.SendCommand(payload)
	defer s.Close()

}

func (s *SerialPort) LightUp() {

	s.LightToVlaue(2900)

}

func (s *SerialPort) LightDown() {

	s.LightToVlaue(0)

}

func (s *SerialPort) Light() {

	s.LightUp()
	time.Sleep(time.Second * 5)
	s.LightDown()

}

func (s *SerialPort) LightToVlaue(value int) {

	s.Open()

	payload := GenCommondLight(value)

	s.SendCommand(payload)
	defer s.Close()

}

func IntToByteArray(n int) [2]byte {
	var result [2]byte

	// 计算低8位（对256取模）
	low := n % 256
	if low < 0 {
		low += 256 // 处理负数情况
	}

	// 计算高8位（右移8位后再对256取模）
	high := (n >> 8) % 256
	if high < 0 {
		high += 256 // 处理负数情况
	}

	// 赋值到字节数组
	result[0] = byte(high)
	result[1] = byte(low)

	return result
}

func GenCommondLight(value int) []byte {

	payload := []byte{0xFE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF}

	res := IntToByteArray(value)
	payload[3] = res[0]
	payload[4] = res[1]

	num := int(payload[3]) + int(payload[4]) + 1

	res2 := IntToByteArray(num)

	payload[6] = res2[1]

	return payload

}
